const axios = require('axios');
const fs = require('fs').promises;
const fsSync = require('fs');
const path = require('path');
const crypto = require('crypto');
const RSCodec = require('./RSCodec.cjs');
const NetworkMonitor = require('./NetworkMonitor.cjs');

class P2PDownloader {
  constructor(options) {
    this.id = options.id;
    this.url = options.url;
    this.savePath = options.savePath;
    this.peers = options.peers || [];
    this.shardCount = options.shardCount;
    this.rsConfig = options.rsConfig;
    
    this.onProgress = options.onProgress;
    this.onComplete = options.onComplete;
    this.onError = options.onError;
    
    this.status = 'pending'; // pending, downloading, paused, completed, error
    this.shards = new Array(this.shardCount).fill(null);
    this.downloadedShards = 0;
    this.totalSize = 0;
    this.downloadedSize = 0;
    this.isPaused = false;
    this.pauseResolve = null;
    
    this.networkMonitor = new NetworkMonitor();
    this.activeDownloads = new Map();
    this.maxConcurrent = 6;
    this.retryCount = 3;
    
    // 断点续传相关
    this.resumeDataPath = this.getResumeDataPath();
    this.tempDir = this.getTempDir();
    
    // 分片哈希表，用于完整性校验
    this.shardHashes = new Map();
    
    // 完整性检查定时器
    this.integrityCheckInterval = null;
    this.integrityCheckIntervalMs = 2000; // 每2秒轻量检查一次
    
    // 优先下载队列（用于丢失的分片）
    this.priorityQueue = [];
    
    // 正在恢复中的分片集合（避免重复恢复）
    this.recoveringShards = new Set();
    
    // 上次检查的时间戳（避免频繁检查）
    this.lastIntegrityCheck = 0;
    
    if (this.rsConfig) {
      this.rsCodec = new RSCodec(this.rsConfig.dataShards, this.rsConfig.parityShards);
      this.requiredShards = this.rsConfig.dataShards;
      console.log(`🔧 RS配置: 数据分片=${this.rsConfig.dataShards}, 冗余分片=${this.rsConfig.parityShards}`);
    } else {
      this.requiredShards = this.shardCount;
    }
    console.log(`📊 初始化: 总分片=${this.shardCount}, 需要分片=${this.requiredShards}`);
  }

  // 获取断点续传数据文件路径
  getResumeDataPath() {
    const hash = crypto.createHash('md5').update(this.url + this.savePath).digest('hex');
    const resumeDir = path.join(process.cwd(), '.download-resume');
    if (!fsSync.existsSync(resumeDir)) {
      fsSync.mkdirSync(resumeDir, { recursive: true });
    }
    return path.join(resumeDir, `${hash}.json`);
  }

  // 获取临时分片存储目录
  getTempDir() {
    const hash = crypto.createHash('md5').update(this.url + this.savePath).digest('hex');
    const tempDir = path.join(process.cwd(), '.download-temp', hash);
    if (!fsSync.existsSync(tempDir)) {
      fsSync.mkdirSync(tempDir, { recursive: true });
    }
    return tempDir;
  }

  // 计算数据的哈希值
  calculateHash(data) {
    return crypto.createHash('sha256').update(data).digest('hex');
  }

  // 轻量级验证：只检查文件是否存在（快速）
  verifyShardExists(index) {
    // 如果内存中有，直接返回true
    if (this.shards[index]) {
      return true;
    }
    
    // 检查文件是否存在
    const shardPath = path.join(this.tempDir, `shard_${index}.bin`);
    return fsSync.existsSync(shardPath);
  }

  // 完整验证：检查文件哈希（慢，只在关键时刻使用）
  async verifyShardIntegrity(index, fullCheck = false) {
    try {
      const shardPath = path.join(this.tempDir, `shard_${index}.bin`);
      
      // 检查文件是否存在
      if (!fsSync.existsSync(shardPath)) {
        console.warn(`⚠️  分片 #${index} 文件不存在`);
        return false;
      }
      
      // 如果不需要完整校验，只检查存在性
      if (!fullCheck) {
        return true;
      }
      
      // 完整校验：验证哈希
      if (this.shards[index]) {
        const fileData = await fs.readFile(shardPath);
        const expectedHash = this.shardHashes.get(index);
        const actualHash = this.calculateHash(fileData);
        
        if (expectedHash && expectedHash !== actualHash) {
          console.warn(`⚠️  分片 #${index} 哈希校验失败`);
          return false;
        }
      }
      
      return true;
    } catch (error) {
      console.error(`验证分片 #${index} 完整性失败:`, error);
      return false;
    }
  }

  // 轻量级检查：只检查文件存在性（用于后台监控）
  checkShardsExistence() {
    const missingShards = [];
    
    for (let i = 0; i < this.shardCount; i++) {
      if (this.shards[i] && !this.verifyShardExists(i)) {
        missingShards.push(i);
      }
    }
    
    return missingShards;
  }

  // 完整检查：包含哈希验证（用于关键节点）
  async checkAllShardsIntegrity(fullCheck = false) {
    const corruptedShards = [];
    
    for (let i = 0; i < this.shardCount; i++) {
      if (this.shards[i]) {
        const isValid = await this.verifyShardIntegrity(i, fullCheck);
        if (!isValid) {
          corruptedShards.push(i);
        }
      }
    }
    
    return corruptedShards;
  }

  // 恢复丢失或损坏的分片
  async recoverCorruptedShards(corruptedIndices) {
    if (corruptedIndices.length === 0) return;
    
    // 过滤掉已经在恢复中的分片
    const newCorruptedIndices = corruptedIndices.filter(idx => !this.recoveringShards.has(idx));
    if (newCorruptedIndices.length === 0) {
      return; // 所有损坏的分片都已在恢复中
    }
    
    console.log(`🔧 检测到 ${newCorruptedIndices.length} 个损坏的分片: [${newCorruptedIndices.join(', ')}]`);
    
    for (const index of newCorruptedIndices) {
      // 标记为正在恢复
      this.recoveringShards.add(index);
      
      // 清除内存中的分片数据
      const hadShard = this.shards[index] !== null;
      if (hadShard) {
        this.downloadedShards--;
        // 重新计算下载大小
        this.downloadedSize = 0;
        for (let i = 0; i < this.shardCount; i++) {
          if (this.shards[i] && i !== index) {
            this.downloadedSize += this.shards[i].length;
          }
        }
        this.shards[index] = null;
        this.shardHashes.delete(index);
        console.log(`  ℹ️  分片 #${index} 已清除，重新计算下载大小: ${(this.downloadedSize / 1024 / 1024).toFixed(2)} MB`);
      }
      
      // 删除损坏的临时文件
      try {
        const shardPath = path.join(this.tempDir, `shard_${index}.bin`);
        if (fsSync.existsSync(shardPath)) {
          await fs.unlink(shardPath);
          console.log(`  🗑️  已删除损坏的临时文件: shard_${index}.bin`);
        }
      } catch (error) {
        console.error(`删除损坏分片 #${index} 失败:`, error);
      }
      
      // 将丢失的分片加入优先队列（如果不在队列或活跃下载中）
      if (!this.priorityQueue.includes(index) && !this.activeDownloads.has(index)) {
        this.priorityQueue.unshift(index); // 加入队列前端，优先下载
        console.log(`  ➕ 分片 #${index} 加入优先下载队列`);
      }
    }
    
    console.log(`🔄 已将 ${newCorruptedIndices.length} 个丢失分片加入优先下载队列`);
    console.log(`📊 当前状态: ${this.downloadedShards}/${this.requiredShards} 个分片，${(this.downloadedSize / 1024 / 1024).toFixed(2)} MB`);
  }

  // 启动完整性检查定时器（轻量级）
  startIntegrityCheck() {
    if (this.integrityCheckInterval) return;
    
    console.log('🛡️  启动轻量级分片监控（仅检查存在性）');
    this.integrityCheckInterval = setInterval(() => {
      if (this.status !== 'downloading' || this.isPaused) return;
      
      try {
        // 使用同步轻量级检查，不阻塞
        const missingShards = this.checkShardsExistence();
        if (missingShards.length > 0) {
          console.log(`⚠️  检测到 ${missingShards.length} 个丢失的分片`);
          // 异步恢复，不阻塞定时器
          this.recoverCorruptedShards(missingShards).catch(err => {
            console.error('恢复分片失败:', err);
          });
        }
      } catch (error) {
        console.error('完整性检查失败:', error);
      }
    }, this.integrityCheckIntervalMs);
  }

  // 停止完整性检查定时器
  stopIntegrityCheck() {
    if (this.integrityCheckInterval) {
      clearInterval(this.integrityCheckInterval);
      this.integrityCheckInterval = null;
      console.log('🛡️  停止分片完整性检查');
    }
  }

  // 立即执行一次完整性检查
  async performIntegrityCheck(fullCheck = false) {
    try {
      // 限流：避免频繁检查
      const now = Date.now();
      if (!fullCheck && (now - this.lastIntegrityCheck) < 1000) {
        return 0; // 1秒内不重复检查
      }
      this.lastIntegrityCheck = now;
      
      const corruptedShards = await this.checkAllShardsIntegrity(fullCheck);
      if (corruptedShards.length > 0) {
        await this.recoverCorruptedShards(corruptedShards);
        return corruptedShards.length;
      }
      return 0;
    } catch (error) {
      console.error('完整性检查失败:', error);
      return 0;
    }
  }

  // 保存下载进度
  async saveProgress() {
    try {
      const progressData = {
        url: this.url,
        savePath: this.savePath,
        peers: this.peers,
        shardCount: this.shardCount,
        rsConfig: this.rsConfig,
        totalSize: this.totalSize,
        downloadedSize: this.downloadedSize,
        downloadedShards: this.downloadedShards,
        shardMap: this.shardMap,
        shardSize: this.shardSize,
        downloadedShardIndices: this.shards.map((shard, idx) => shard ? idx : null).filter(i => i !== null),
        shardHashes: Array.from(this.shardHashes.entries()),
        timestamp: Date.now()
      };
      
      await fs.writeFile(this.resumeDataPath, JSON.stringify(progressData, null, 2));
    } catch (error) {
      console.error('保存进度失败:', error);
    }
  }

  // 加载之前的下载进度
  async loadProgress() {
    try {
      if (!fsSync.existsSync(this.resumeDataPath)) {
        return false;
      }

      const data = await fs.readFile(this.resumeDataPath, 'utf-8');
      const progressData = JSON.parse(data);

      // 验证数据是否匹配
      if (progressData.url !== this.url || progressData.savePath !== this.savePath) {
        return false;
      }

      console.log('📂 发现断点续传数据');
      console.log(`   上次下载时间: ${new Date(progressData.timestamp).toLocaleString()}`);
      console.log(`   已下载: ${progressData.downloadedShards}/${progressData.shardCount} 个分片`);

      // 恢复数据
      this.totalSize = progressData.totalSize;
      this.downloadedSize = progressData.downloadedSize;
      this.downloadedShards = progressData.downloadedShards;
      this.shardMap = progressData.shardMap;
      this.shardSize = progressData.shardSize;

      // 恢复哈希表
      if (progressData.shardHashes) {
        this.shardHashes = new Map(progressData.shardHashes);
      }

      // 加载已下载的分片并验证完整性
      let validCount = 0;
      let corruptedCount = 0;
      
      for (const idx of progressData.downloadedShardIndices) {
        const shardPath = path.join(this.tempDir, `shard_${idx}.bin`);
        if (fsSync.existsSync(shardPath)) {
          const shardData = await fs.readFile(shardPath);
          const expectedHash = this.shardHashes.get(idx);
          
          // 验证哈希（如果有）
          if (expectedHash) {
            const actualHash = this.calculateHash(shardData);
            if (actualHash === expectedHash) {
              this.shards[idx] = shardData;
              validCount++;
            } else {
              console.warn(`⚠️  分片 #${idx} 校验失败，将重新下载`);
              this.shardHashes.delete(idx);
              corruptedCount++;
              this.downloadedShards--;
              this.downloadedSize -= shardData.length;
            }
          } else {
            // 如果没有哈希，直接加载
            this.shards[idx] = shardData;
            this.shardHashes.set(idx, this.calculateHash(shardData));
            validCount++;
          }
        } else {
          console.warn(`⚠️  分片 #${idx} 文件丢失，将重新下载`);
          this.downloadedShards--;
          this.shardHashes.delete(idx);
          corruptedCount++;
        }
      }

      console.log(`✅ 成功加载 ${validCount} 个有效分片`);
      if (corruptedCount > 0) {
        console.log(`⚠️  发现 ${corruptedCount} 个损坏或丢失的分片，将重新下载`);
      }

      return true;
    } catch (error) {
      console.error('加载进度失败:', error);
      return false;
    }
  }

  // 保存单个分片到临时目录
  async saveShardToTemp(index, data) {
    try {
      const shardPath = path.join(this.tempDir, `shard_${index}.bin`);
      await fs.writeFile(shardPath, data);
    } catch (error) {
      console.error(`保存分片 #${index} 失败:`, error);
    }
  }

  // 清理断点续传数据
  async cleanupResumeData() {
    try {
      // 删除进度文件
      if (fsSync.existsSync(this.resumeDataPath)) {
        await fs.unlink(this.resumeDataPath);
      }
      
      // 删除临时分片目录
      if (fsSync.existsSync(this.tempDir)) {
        await fs.rm(this.tempDir, { recursive: true, force: true });
      }
      
      console.log('🧹 清理断点续传数据完成');
    } catch (error) {
      console.error('清理断点续传数据失败:', error);
    }
  }

  async start() {
    try {
      this.status = 'downloading';
      console.log(`\n🎬 开始下载流程: ${this.url}`);
      
      // 检查是否为直接下载
      if (this.url.startsWith('http://') || this.url.startsWith('https://')) {
        console.log('📦 模式: 直接 HTTP 下载');
        await this.directDownload();
      } else {
        console.log('🔗 模式: P2P 分片下载');
        
        // 尝试加载断点续传数据
        const resumed = await this.loadProgress();
        
        if (!resumed) {
          // 获取文件元数据
          console.log('\n📋 步骤 1/5: 获取文件元数据');
          await this.fetchMetadata();
        } else {
          console.log('\n♻️  步骤 1/5: 从断点恢复下载');
        }
        
        // 启动完整性检查
        this.startIntegrityCheck();
        
        // 开始下载分片
        console.log('\n📥 步骤 2/5: 下载文件分片');
        await this.downloadShards();
        
        // 停止完整性检查定时器
        this.stopIntegrityCheck();
        
        // 在RS恢复前进行完整哈希校验
        console.log('\n🔍 RS恢复前完整性校验（含哈希）...');
        const preRsCheck = await this.performIntegrityCheck(true); // fullCheck = true
        if (preRsCheck > 0) {
          console.log(`⚠️  发现 ${preRsCheck} 个损坏的分片，已标记重新下载`);
          // 如果有损坏的分片需要重新下载
          if (this.priorityQueue.length > 0) {
            console.log('🔄 重新下载损坏的分片...');
            await this.downloadShards();
          }
        }
        
        // 如果有 RS 码，进行解码
        if (this.rsConfig && this.downloadedShards < this.shardCount) {
          console.log('\n🔧 步骤 3/5: Reed-Solomon 恢复');
          await this.recoverWithRS();
        } else {
          console.log('\n✓ 步骤 3/5: 跳过（所有分片已下载）');
        }
        
        // 合并前进行最终完整哈希校验
        console.log('\n🔍 合并前最终完整性校验（含哈希）...');
        const finalCheck = await this.performIntegrityCheck(true); // fullCheck = true
        if (finalCheck > 0) {
          console.log(`⚠️  合并前发现 ${finalCheck} 个损坏的分片，尝试恢复...`);
          
          // 尝试重新下载损坏的分片
          if (this.priorityQueue.length > 0) {
            console.log('🔄 重新下载损坏的分片...');
            // 重新启动监控
            this.startIntegrityCheck();
            await this.downloadShards();
            this.stopIntegrityCheck();
            
            // 再次检查
            const recheckCount = await this.performIntegrityCheck(true);
            if (recheckCount > 0) {
              // 如果还有损坏，尝试用RS恢复
              if (this.rsConfig && this.downloadedShards >= this.rsConfig.dataShards) {
                console.log('🔧 使用RS码尝试恢复剩余损坏的分片...');
                await this.recoverWithRS();
                
                // 最终检查
                const finalRecheckCount = await this.performIntegrityCheck(true);
                if (finalRecheckCount > 0) {
                  throw new Error(`无法恢复所有分片：仍有 ${finalRecheckCount} 个分片损坏`);
                }
              } else {
                throw new Error(`无法恢复所有分片：仍有 ${recheckCount} 个分片损坏`);
              }
            }
          } else {
            throw new Error(`合并前发现 ${finalCheck} 个损坏的分片，且无法加入恢复队列`);
          }
        }
        
        // 合并文件
        console.log('\n🔨 步骤 4/5: 合并分片');
        await this.mergeShards();
        
        // 清理断点续传数据
        console.log('\n🧹 步骤 5/5: 清理临时文件');
        await this.cleanupResumeData();
      }
      
      this.status = 'completed';
      console.log(`\n🎉 下载完成！文件保存在: ${this.savePath}\n`);
      
      this.onComplete({ 
        path: this.savePath,
        size: this.totalSize
      });
    } catch (error) {
      // 停止完整性检查
      this.stopIntegrityCheck();
      
      if (error.message === '下载已暂停') {
        console.log('\n⏸️  下载已暂停，进度已保存');
        await this.saveProgress();
        return;
      }
      
      console.error('\n💥 下载失败:', error.message);
      console.error(error.stack);
      this.status = 'error';
      
      // 保存进度以便下次恢复
      await this.saveProgress();
      
      this.onError(error);
    }
  }

  async directDownload() {
    try {
      console.log('📥 开始直接下载:', this.url);
      
      let lastUpdate = Date.now();
      let lastBytes = 0;
      
      const response = await axios.get(this.url, {
        responseType: 'arraybuffer',
        timeout: 300000, // 5 分钟超时
        onDownloadProgress: (progressEvent) => {
          this.totalSize = progressEvent.total || progressEvent.loaded;
          this.downloadedSize = progressEvent.loaded || 0;
          
          // 计算速度
          const now = Date.now();
          const timeDiff = (now - lastUpdate) / 1000; // 秒
          const bytesDiff = this.downloadedSize - lastBytes;
          const currentSpeed = timeDiff > 0 ? bytesDiff / timeDiff : 0;
          
          lastUpdate = now;
          lastBytes = this.downloadedSize;
          
          const progress = {
            total: this.totalSize,
            downloaded: this.downloadedSize,
            percentage: this.totalSize > 0 ? (this.downloadedSize / this.totalSize) * 100 : 0,
            shards: {
              total: 1,
              downloaded: this.downloadedSize === this.totalSize && this.totalSize > 0 ? 1 : 0,
              required: 1
            },
            speed: currentSpeed,
            eta: currentSpeed > 0 ? Math.ceil((this.totalSize - this.downloadedSize) / currentSpeed) : -1
          };
          
          this.onProgress(progress);
        }
      });
      
      console.log(`✅ 下载完成，大小: ${response.data.byteLength} 字节`);
      
      // 确保保存目录存在
      const dir = path.dirname(this.savePath);
      await fs.mkdir(dir, { recursive: true });
      
      // 保存文件
      await fs.writeFile(this.savePath, Buffer.from(response.data));
      
      console.log('💾 文件已保存:', this.savePath);
      
      this.totalSize = response.data.byteLength;
    } catch (error) {
      console.error('❌ 直接下载失败:', error.message);
      throw new Error(`直接下载失败: ${error.message}`);
    }
  }

  async fetchMetadata() {
    console.log('📡 获取文件元数据...');
    console.log('节点列表:', this.peers);
    console.log('URL:', this.url);
    
    // 从 URL 中提取 fileId
    let fileId = null;
    try {
      const url = new URL(this.url);
      fileId = url.searchParams.get('fileId');
      console.log('提取的 fileId:', fileId);
    } catch (e) {
      console.log('URL 解析失败，使用原始 URL');
    }
    
    // 从任意可用节点获取文件元数据
    for (const peer of this.peers) {
      try {
        console.log(`尝试从节点获取元数据: ${peer}`);
        
        const response = await axios.get(`${peer}/metadata`, {
          params: fileId ? { fileId } : { file: this.url },
          timeout: 5000
        });
        
        const { totalSize, shardSize, shards } = response.data;
        this.totalSize = totalSize;
        this.shardSize = shardSize;
        this.shardMap = shards; // 每个分片在哪些节点上
        
        console.log(`✅ 元数据获取成功: 总大小=${totalSize}, 分片大小=${shardSize}, 分片数=${shards.length}`);
        return;
      } catch (error) {
        console.error(`❌ 节点 ${peer} 失败:`, error.message);
        continue;
      }
    }
    
    throw new Error('无法获取文件元数据，所有节点不可达');
  }

  async downloadShards() {
    console.log(`\n🚀 开始下载分片: 总数=${this.shardCount}, 需要=${this.requiredShards}`);
    console.log(`   已下载: ${this.downloadedShards} 个分片`);
    console.log(`   优先队列: ${this.priorityQueue.length} 个分片`);
    
    // 创建队列，排除已下载的分片
    const queue = [];
    for (let i = 0; i < this.shardCount; i++) {
      if (!this.shards[i]) {
        queue.push(i);
      }
    }
    
    console.log(`📋 待下载分片队列: ${queue.length} 个`);
    console.log(`📊 当前下载大小: ${(this.downloadedSize / 1024 / 1024).toFixed(2)} MB`);
    
    while ((queue.length > 0 || this.priorityQueue.length > 0 || this.activeDownloads.size > 0)) {
      // 检查暂停状态
      if (this.isPaused) {
        console.log('⏸️  下载已暂停，等待恢复...');
        
        // 等待所有活跃下载完成
        if (this.activeDownloads.size > 0) {
          await Promise.all(Array.from(this.activeDownloads.values()));
        }
        
        // 保存进度
        await this.saveProgress();
        
        // 等待恢复信号
        await new Promise(resolve => {
          this.pauseResolve = resolve;
        });
        
        console.log('▶️  下载已恢复');
        this.pauseResolve = null;
      }
      
      if (this.status === 'cancelled') {
        throw new Error('下载已取消');
      }
      
      // 填充下载队列 - 优先处理优先队列中的分片
      while (this.activeDownloads.size < this.maxConcurrent && (this.priorityQueue.length > 0 || queue.length > 0)) {
        let shardIndex;
        let isPriority = false;
        
        // 优先从优先队列获取
        if (this.priorityQueue.length > 0) {
          shardIndex = this.priorityQueue.shift();
          isPriority = true;
          
          // 确保该分片确实需要下载
          if (this.shards[shardIndex]) {
            continue; // 已经下载了，跳过
          }
          
          // 从普通队列中移除（如果存在）
          const queueIndex = queue.indexOf(shardIndex);
          if (queueIndex !== -1) {
            queue.splice(queueIndex, 1);
          }
          
          console.log(`🚨 优先下载丢失的分片 #${shardIndex} (活跃: ${this.activeDownloads.size}/${this.maxConcurrent})`);
        } else {
          shardIndex = queue.shift();
          console.log(`➕ 添加分片 #${shardIndex} 到下载队列 (活跃: ${this.activeDownloads.size}/${this.maxConcurrent})`);
        }
        
        const downloadPromise = this.downloadShard(shardIndex, isPriority)
          .then(() => {
            console.log(`✅ 分片 #${shardIndex} 下载完成`);
            this.activeDownloads.delete(shardIndex);
            // 从恢复集合中移除
            this.recoveringShards.delete(shardIndex);
          })
          .catch((error) => {
            console.error(`❌ 分片 #${shardIndex} 下载失败:`, error.message);
            // 重试逻辑
            if (this.downloadedShards < this.requiredShards) {
              if (isPriority) {
                console.log(`🔄 分片 #${shardIndex} 重新加入优先队列`);
                this.priorityQueue.push(shardIndex);
              } else {
                console.log(`🔄 分片 #${shardIndex} 重新加入队列`);
                queue.push(shardIndex);
              }
            } else {
              // 从恢复集合中移除
              this.recoveringShards.delete(shardIndex);
            }
            this.activeDownloads.delete(shardIndex);
          });
        
        this.activeDownloads.set(shardIndex, downloadPromise);
      }
      
      // 等待至少一个下载完成
      if (this.activeDownloads.size > 0) {
        await Promise.race(Array.from(this.activeDownloads.values()));
      }
      
      // 检查是否已经下载足够的分片
      if (this.downloadedShards >= this.requiredShards && this.priorityQueue.length === 0) {
        console.log(`🎉 已下载足够的分片: ${this.downloadedShards}/${this.requiredShards}`);
        break;
      }
    }
    
    // 下载完成后进行轻量级检查（只检查存在性）
    console.log('\n🔍 进行最终存在性检查...');
    const missingShards = this.checkShardsExistence();
    if (missingShards.length > 0) {
      console.log(`⚠️  发现 ${missingShards.length} 个丢失的分片: [${missingShards.join(', ')}]`);
      await this.recoverCorruptedShards(missingShards);
      
      // 如果发现损坏的分片，继续下载循环
      if (this.priorityQueue.length > 0) {
        console.log(`🔄 优先队列有 ${this.priorityQueue.length} 个分片待下载，继续下载...`);
        await this.downloadShards(); // 递归调用以下载恢复的分片
      } else {
        console.warn('⚠️  警告：发现丢失的分片，但优先队列为空！');
      }
    }
    
    console.log(`\n✨ 分片下载完成，共下载 ${this.downloadedShards} 个分片`);
    console.log(`📊 总下载大小: ${(this.downloadedSize / 1024 / 1024).toFixed(2)} MB`);
  }

  async downloadShard(shardIndex, isPriority = false) {
    // 获取该分片所在的节点索引
    const peerIndices = this.shardMap[shardIndex] || [0];
    
    // 将索引转换为实际的节点 URL
    const availablePeers = peerIndices.map(idx => this.peers[idx]).filter(p => p);
    
    // 如果没有可用节点，使用所有节点
    const peersToUse = availablePeers.length > 0 ? availablePeers : this.peers;
    
    // 根据网络状况选择最佳节点
    const bestPeer = await this.networkMonitor.selectBestPeer(peersToUse);
    console.log(`📥 下载分片 #${shardIndex} 从节点: ${bestPeer}`);
    
    // 从 URL 中提取 fileId
    let fileId = null;
    try {
      const url = new URL(this.url);
      fileId = url.searchParams.get('fileId');
    } catch (e) {
      // 忽略
    }
    
    for (let retry = 0; retry < this.retryCount; retry++) {
      try {
        const url = `${bestPeer}/shard`;
        const params = fileId ? { fileId, index: shardIndex } : { file: this.url, index: shardIndex };
        
        console.log(`  请求分片 #${shardIndex}:`, url, params);
        
        const response = await axios.get(url, {
          params,
          responseType: 'arraybuffer',
          timeout: 30000,
          onDownloadProgress: (progressEvent) => {
            this.updateProgress();
          }
        });
        
        this.shards[shardIndex] = Buffer.from(response.data);
        this.downloadedShards++;
        this.downloadedSize += this.shards[shardIndex].length;
        
        // 计算并保存分片哈希
        const shardHash = this.calculateHash(this.shards[shardIndex]);
        this.shardHashes.set(shardIndex, shardHash);
        
        console.log(`  ✓ 分片 #${shardIndex} 下载成功，大小: ${this.shards[shardIndex].length} 字节`);
        
        // 保存分片到临时目录（断点续传）
        await this.saveShardToTemp(shardIndex, this.shards[shardIndex]);
        
        // 定期保存进度（每 10 个分片）
        if (this.downloadedShards % 10 === 0) {
          await this.saveProgress();
        }
        
        // 更新节点速度统计
        this.networkMonitor.recordSuccess(bestPeer, this.shards[shardIndex].length);
        
        this.updateProgress();
        return;
      } catch (error) {
        console.error(`  ✗ 分片 #${shardIndex} 下载失败 (尝试 ${retry + 1}/${this.retryCount}):`, error.message);
        this.networkMonitor.recordFailure(bestPeer);
        
        if (retry === this.retryCount - 1) {
          throw error;
        }
        
        // 指数退避
        const delay = Math.pow(2, retry) * 1000;
        console.log(`  ⏳ 等待 ${delay}ms 后重试...`);
        await new Promise(resolve => setTimeout(resolve, delay));
      }
    }
  }

  async recoverWithRS() {
    try {
      console.log('\n🔧 使用 Reed-Solomon 码恢复丢失的分片...');
      
      // 收集已下载的分片和它们的索引
      const availableShards = [];
      const availableIndices = [];
      
      for (let i = 0; i < this.shards.length; i++) {
        if (this.shards[i]) {
          availableShards.push(this.shards[i]);
          availableIndices.push(i);
        }
      }
      
      console.log(`📊 统计: 已下载 ${availableShards.length}/${this.shardCount} 个分片`);
      console.log(`   需要: ${this.rsConfig.dataShards} 个数据分片`);
      console.log(`   可用索引:`, availableIndices.slice(0, 10), '...');
      
      if (availableShards.length < this.rsConfig.dataShards) {
        throw new Error(`无法恢复：需要至少 ${this.rsConfig.dataShards} 个分片，但只有 ${availableShards.length} 个`);
      }
      
      // 检查是否所有数据分片都已下载
      let missingDataShards = [];
      for (let i = 0; i < this.rsConfig.dataShards; i++) {
        if (!this.shards[i]) {
          missingDataShards.push(i);
        }
      }
      
      if (missingDataShards.length === 0) {
        console.log('✅ 所有数据分片已完整，跳过恢复');
        return;
      }
      
      console.log(`🔨 需要恢复 ${missingDataShards.length} 个数据分片:`, missingDataShards);
      
      // 使用前 dataShards 个可用分片进行恢复
      const shardsForRecovery = availableShards.slice(0, this.rsConfig.dataShards);
      const indicesForRecovery = availableIndices.slice(0, this.rsConfig.dataShards);
      
      console.log('🔄 使用的分片索引:', indicesForRecovery);
      
      // 恢复所有数据分片
      const recoveredShards = await this.rsCodec.decode(
        shardsForRecovery,
        indicesForRecovery
      );
      
      // 填充恢复的分片（只恢复缺失的数据分片）
      let recoveredCount = 0;
      for (let i = 0; i < this.rsConfig.dataShards; i++) {
        if (!this.shards[i]) {
          this.shards[i] = recoveredShards[i];
          this.downloadedShards++;
          recoveredCount++;
          
          // 计算并保存恢复分片的哈希
          const shardHash = this.calculateHash(this.shards[i]);
          this.shardHashes.set(i, shardHash);
          
          // 保存恢复的分片到临时目录
          await this.saveShardToTemp(i, this.shards[i]);
          
          console.log(`  ✓ 恢复分片 #${i}`);
        }
      }
      
      console.log(`✅ 成功恢复 ${recoveredCount} 个分片`);
    } catch (error) {
      console.error('❌ RS 恢复详细错误:', error);
      throw new Error(`RS 码恢复失败: ${error.message}`);
    }
  }

  async mergeShards() {
    try {
      console.log('\n📦 开始合并分片...');
      console.log(`   RS配置: ${this.rsConfig ? JSON.stringify(this.rsConfig) : '无'}`);
      console.log(`   总分片数: ${this.shardCount}`);
      console.log(`   已下载分片数: ${this.downloadedShards}`);
      
      // 确保保存目录存在
      const dir = path.dirname(this.savePath);
      await fs.mkdir(dir, { recursive: true });
      
      // 只合并数据分片（如果使用了 RS 码）
      const dataShards = this.rsConfig 
        ? this.shards.slice(0, this.rsConfig.dataShards)
        : this.shards;
      
      // 验证所有必需的分片都存在
      const requiredCount = this.rsConfig ? this.rsConfig.dataShards : this.shardCount;
      const missingIndices = [];
      
      console.log(`   需要合并: ${requiredCount} 个数据分片`);
      
      for (let i = 0; i < requiredCount; i++) {
        if (!dataShards[i]) {
          missingIndices.push(i);
        }
      }
      
      if (missingIndices.length > 0) {
        throw new Error(`无法合并：缺少 ${missingIndices.length} 个必需的数据分片 [${missingIndices.join(', ')}]`);
      }
      
      // 显示每个分片的大小
      console.log('   分片大小统计:');
      let totalBytes = 0;
      for (let i = 0; i < Math.min(5, dataShards.length); i++) {
        console.log(`     分片 #${i}: ${dataShards[i].length} 字节`);
        totalBytes += dataShards[i].length;
      }
      if (dataShards.length > 5) {
        console.log(`     ... 还有 ${dataShards.length - 5} 个分片`);
        for (let i = 5; i < dataShards.length; i++) {
          totalBytes += dataShards[i].length;
        }
      }
      
      console.log(`   预计合并大小: ${(totalBytes / 1024 / 1024).toFixed(2)} MB`);
      console.log(`   元数据中的总大小: ${(this.totalSize / 1024 / 1024).toFixed(2)} MB`);
      
      // 合并所有分片
      const mergedData = Buffer.concat(dataShards);
      const actualSize = mergedData.length;
      
      await fs.writeFile(this.savePath, mergedData);
      
      console.log(`\n✅ 文件合并完成！`);
      console.log(`   实际大小: ${(actualSize / 1024 / 1024).toFixed(2)} MB (${actualSize} 字节)`);
      console.log(`   预期大小: ${(this.totalSize / 1024 / 1024).toFixed(2)} MB (${this.totalSize} 字节)`);
      
      if (actualSize !== this.totalSize) {
        console.warn(`⚠️  警告：实际大小与预期大小不一致！差异: ${actualSize - this.totalSize} 字节`);
      }
      
      // 更新实际的总大小（以合并后的实际大小为准）
      this.totalSize = actualSize;
    } catch (error) {
      throw new Error(`文件合并失败: ${error.message}`);
    }
  }

  updateProgress() {
    const progress = {
      total: this.totalSize,
      downloaded: this.downloadedSize,
      percentage: this.totalSize > 0 ? (this.downloadedSize / this.totalSize) * 100 : 0,
      shards: {
        total: this.shardCount,
        downloaded: this.downloadedShards,
        required: this.requiredShards
      },
      speed: this.networkMonitor.getAverageSpeed(),
      eta: this.networkMonitor.getETA(this.totalSize - this.downloadedSize)
    };
    
    this.onProgress(progress);
  }

  async pause() {
    console.log('🔴 触发暂停...');
    this.isPaused = true;
    this.status = 'paused';
    // 暂停时停止完整性检查
    this.stopIntegrityCheck();
  }

  async resume() {
    console.log('🟢 触发恢复...');
    this.isPaused = false;
    
    if (this.status === 'paused') {
      this.status = 'downloading';
      
      // 如果正在等待，发送恢复信号
      if (this.pauseResolve) {
        this.pauseResolve();
        this.pauseResolve = null;
        // 恢复时重新启动完整性检查
        this.startIntegrityCheck();
      } else {
        // 如果不在下载中，重新开始
        this.start().catch(err => {
          console.error('恢复下载失败:', err);
          this.onError(err);
        });
      }
    }
  }

  async cancel() {
    console.log('❌ 取消下载...');
    this.status = 'cancelled';
    this.isPaused = false;
    
    // 停止完整性检查
    this.stopIntegrityCheck();
    
    if (this.pauseResolve) {
      this.pauseResolve();
      this.pauseResolve = null;
    }
    
    // 清理断点续传数据
    await this.cleanupResumeData();
  }
}

module.exports = P2PDownloader;

